<%
'######################################################################
'## App.Dao.asp
'## -------------------------------------------------------------------
'## Feature     :   App Dao
'## Version     :   v0.1
'## Author      :   Lajox (lajox@19www.com)
'## Update Date :   2014/12/11 1:52
'## HomePage	:   http://www.19www.com
'## -------------------------------------------------------------------
'## Description :   App Dao Core
'######################################################################

Class Cls_App_Dao

	Private s_fsoName, s_dictName, s_steamName, s_Charset, s_tbPrefix
	Private s_selectSql, s_insertSql, s_updateSql, s_deleteSql, s_querySql, s_execType, s_execSql
	Private o_db, o_ds, o_fs, o_ds_join, o_ds_on
	Private b_changed
	Private i_find, i_affected, i_join

	Private Sub Class_Initialize()
		On Error Resume Next
		s_Charset = App.CharSet
		s_tbPrefix = App.tbPrefix
		s_dictName = AB.dictName
		AB.Use "H" : AB.Use "A" : AB.Use "db"
		s_selectSql = "SELECT%TOP% %FIELD% FROM %TABLE%%ALIAS%%JOINON%%WHERE%%GROUP%%HAVING%%ORDER%%UNION%"
		s_insertSql = "INSERT INTO %TABLE%%WHERE%"
		s_updateSql = "UPTATE %TABLE%%SET%"
		s_deleteSql = "DELETE FROM %TABLE%%WHERE%"
		s_querySql = ""
		s_execType = 1
		i_affected = 0
		i_join = 0
		i_find = 999
		b_changed = False
		Set o_ds = AB.C.Dict() : o_ds("table") = "TABLE"
		Set o_fs = AB.C.Dict()
		Set o_ds_join = AB.C.Dict()
		Set o_ds_on = AB.C.Dict()
		Init()
		On Error GoTo 0
	End Sub

	Private Sub Class_Terminate()
		Set o_db = Nothing
		Set o_ds = Nothing
		Set o_fs = Nothing
		Set o_ds_join = Nothing
		Set o_ds_on = Nothing
	End Sub

	Private Sub Init()
		On Error Resume Next
		If AB.C.IsDict(App.dbCfg) Then
			Dim dbCfg : Set dbCfg = App.dbCfg
			If LCase(dbCfg("db_open"))="true" Or LCase(dbCfg("db_open"))="1" Or LCase(dbCfg("db_open"))="" Then
				AB.Da "dbtype", dbCfg("db_type") '@dbtype(acc/sql)
				AB.Da "accdb", dbCfg("acc_db") '@acc.db
				AB.Da "accpwd", dbCfg("acc_pwd") '@acc.pwd
				AB.Da "sqlserver", dbCfg("sql_server") '@sql.server
				AB.Da "sqldb", dbCfg("sql_db") '@sql.db
				AB.Da "sqluid", dbCfg("sql_uid") '@sql.uid
				AB.Da "sqlpwd", dbCfg("sql_pwd") '@sql.pwd
				'--- 设置数据表前缀
				s_tbPrefix = App.tbPrefix
				'将App.Dao.db托管给ab.db
				If (IsObject(App.db) And LCase(TypeName(App.db)) = "cls_ab_db") Then
					Set o_db = App.db
				Else
					Rem ----
					If LCase(AB.DT("dbtype"))="sql" Or LCase(AB.DT("dbtype"))="mssql" Then '@MS SQL Server
						AB.db.Conn = AB.db.OpenConn(0,AB.DT("sqldb"),""&AB.DT("sqluid")&":"&AB.DT("sqlpwd")&"@"&AB.DT("sqlserver")&"")
					Else '@Access
						AB.db.Conn = AB.db.OpenConn(1,AB.DT("accdb"),AB.DT("accpwd"))
					End If
					If AB.C.IsNul(AB.db.Conn) Then
						AB.ShowErr "", "数据库连接失败。(查看具体信息，请设置 <font color=red>App.Dubug = True</font>)"
						AB.Exit()
					End If
					App.db = AB.db : Set o_db = AB.db
				End If
			Else
				App.Out.Put "数据库连接已关闭"
			End If
			Set dbCfg = Nothing
		Else
			App.Out.Put "没有正确配置数据库信息"
		End If
		On Error Goto 0
	End Sub

	Public Function [New]()
		Set [New] = New Cls_App_Dao
	End Function

	Public Property Let db(ByVal o)
		If IsObject(o) Then Set o_db = o
	End Property
	Public Property Get db()
		Set db = o_db
	End Property

	Public Property Let tbPrefix(ByVal s)
		s_tbPrefix = s
	End Property
	Public Property Get tbPrefix()
		tbPrefix = s_tbPrefix
	End Property
	Public Function B(ByVal s)
        s_tbPrefix = s
		Set B = Me
    End Function

	Public Property Let Table(ByVal s)
		o_ds("table") = Trim(s)
		If Instr(s," ")>0 Then
			o_ds("table") = Trim(AB.C.CLeft(s," "))
			o_ds("alias") = Trim(AB.C.CRight(s," "))
		End If
	End Property
	Public Property Get Table()
		Table = o_ds("table")
	End Property

	Public Function T(ByVal s)
        If Not AB.C.IsNul(Trim(s)) Then o_ds("table") = Trim(s)
		If Instr(o_ds("table")," ")>0 Then
			o_ds("table") = Trim(AB.C.CLeft(o_ds("table")," "))
			o_ds("alias") = Trim(AB.C.CRight(o_ds("table")," "))
		End If
		Set T = Me
    End Function
	Public Function From(ByVal s) : Set From = Me.T(s) : End Function

	Public Function [Alias](ByVal s)
        If Not AB.C.IsNul(Trim(s)) Then o_ds("alias") = Trim(s)
		Set [Alias] = Me
    End Function
	Public Function A(ByVal s) : Set A = Me.Alias(s) : End Function

	Public Function GetAlias()
		Dim s
		If o_ds.Exists("alias") Then
			s = Trim(o_ds("alias"))
		Else
			If Instr(o_ds("table")," ")>0 Then
				o_ds("table") = Trim(AB.C.CLeft(o_ds("table")," "))
				o_ds("alias") = Trim(AB.C.CRight(o_ds("table")," "))
			End If
			s = Trim(o_ds("alias"))
		End If
        GetAlias = s
    End Function

	Public Function [Select](ByVal s)
		Set [Select] = Me.Field(s)
    End Function

	Public Function Field(ByVal s)
        If Not AB.C.IsNul(s) Then
			If IsObject(s) Then Set o_ds("field") = s Else o_ds("field") = s
		Else
			o_ds("field") = "*"
		End If
		Set Field = Me
    End Function

	Public Function Where(ByVal s)
		If AB.C.isStr(s) Then s = Trim(s)
        If Not AB.C.IsNul(s) Then
			If IsObject(s) Then Set o_ds("where") = s Else o_ds("where") = s
		End If
		Set Where = Me
    End Function

	Public Function Order(ByVal s)
        If Not AB.C.IsNul(s) Then o_ds("order") = s
		Set Order = Me
    End Function

	Public Function Group(ByVal s)
        If Not AB.C.IsNul(s) Then o_ds("group") = s
		Set Group = Me
    End Function

	Public Function Having(ByVal s)
        If Not AB.C.IsNul(s) Then o_ds("having") = s
		Set Having = Me
    End Function

	Public Function [Join](ByVal s)
        If Not AB.C.IsNul(s) Then
			i_join = i_join + 1
			If IsObject(s) Then Set o_ds_join(i_join) = s Else o_ds_join(i_join) = s
		End If
		Set [Join] = Me
    End Function

	Public Function [On](ByVal s)
        If Not AB.C.IsNul(s) Then  o_ds_on(i_join) = s
		Set [On] = Me
    End Function

	Public Function Union(ByVal s)
        If Not AB.C.IsNul(s) Then o_ds("union") = s
		Set Union = Me
    End Function

	Public Function Relation(ByVal s)
        If Not AB.C.IsNul(s) Then
			If IsObject(s) Then Set o_ds("relation") = s Else o_ds("relation") = s
		End If
		Set Relation = Me
    End Function

	Public Function Top(ByVal s)
        If Trim(s)<>"" Then o_ds("top") = s
		Set Top = Me
    End Function

	'模拟 mysql的 limit(offset,rows) 用法
	'用法：
	'limit(0,0) 取全部数据（第1条(0+1=1)数据开始到结束的数据）
	'limit(0,1) 取从（第1条(0+1=1)数据开始的1条数据，即：第1~1条）（共1条）
	'limit(3,0) 取从（第4条(3+1=4)数据开始到结束的数据，即：第4~最后一条）
	'limit(2,5) 表示 第3条(2+1=3)数据开始的5条数据，即：第3~第7条）（共5条）
	'limit(1,2) 表示 第2条(1+1=2)数据开始的2条数据，即：第2~第3条）（共2条）
	'limit(4,6) 可以这么算：表示 第4+1=5条 到 第4+6=10条）（共6条）
	'@注意：Limit用法只能用于查询，不能用于Rs数据更新！
	Public Function Limit(ByVal offset, ByVal rows)
		On Error Resume Next
		o_ds("offset") = AB.C.IIF(AB.C.IsNum(offset),CLng(offset),0)
		o_ds("rows") = AB.C.IIF(AB.C.IsNum(rows),CLng(rows),0)
		Set Limit = Me
		On Error Goto 0
    End Function

	'取得当前Rs的字段值, 单个为字符串，多个为数组
	'若想返回多个纪录的数组，可以这么做，后面加个:1或:true字符，例：getField("name:1")，getField("id,name:1")
	Public Function getField(ByVal p)
		On Error Resume Next
        Dim tRs, fields, i, a, t, m, arr : t = Empty : a = Array() : arr = Array()
		Set tRs = Me.Result()
		fields = Me.RsFields(tRs)
		If Not (tRs.Bof Or tRs.Eof) and Not AB.C.IsNul(p) Then
			If AB.C.isStr(p) Then
				If InStr(p,":")>0 Then
					m = Trim(AB.C.CRight(p,":"))
					p = AB.C.CLeft(p,":")
					If m<>"" Then m = CBool(m)
				End If
			End If
			AB.Use "A"
			If Not IsArray(p) Then p = Split(p, ",")
			If m Then
				Do While Not tRs.Eof
					a = Array()
					For Each i In p
						If Trim(i)<>"" Then
							If (AB.A.InArray(Trim(i),fields) Or InStr(Trim(i),".")>0) Then a = AB.A.Push(a, tRs(Trim(i)).Value)
						End If
					Next
					If AB.A.Len(a)=1 Then t = a(0) Else t = a
					arr = AB.A.Push(arr, t)
					tRs.MoveNext
				Loop
				t = arr
			Else
				For Each i In p
					If Trim(i)<>"" Then
						If (AB.A.InArray(Trim(i),fields) Or InStr(Trim(i),".")>0) Then a = AB.A.Push(a, tRs(Trim(i)).Value)
					End If
				Next
				If AB.A.Len(a)=1 Then t = a(0) Else t = a
			End If
		End If
		tRs.Close() : Set tRs = Nothing
		getField = AB.C.IfHas(t, "")
		On Error Goto 0
    End Function

	'取得当前Rs的字段名集合（数组）
	Public Function GetFields()
        Dim Rs, i, f, a : a = Array()
		AB.Use "A"
		Set Rs = Me.Result()
		For i = 0 To Rs.Fields.Count-1
			f = Rs.Fields(i).Name
			a = AB.A.Push(a, f)
		Next
		Rs.Close() : Set Rs = Nothing
		GetFields = a
    End Function

	'取得Rs的字段集合（数组）
	Public Function RsFields(ByVal Rs)
        Dim i, f, a : a = Array()
		AB.Use "A"
		If AB.C.IsRs(Rs) Then
			For i = 0 To Rs.Fields.Count-1
				f = Rs.Fields(i).Name
				a = AB.A.Push(a, f)
			Next
		End If
		RsFields = a
    End Function

	'检测是否含某字段
	Public Function HasField(ByVal p)
		AB.Use "A"
		Dim fields : fields = Me.GetFields()
		HasField = AB.A.InArray(p, fields)
    End Function

	'取得当前查询表的字段名集合（数组）
	Public Function tbFields()
        Dim Rs, i, f, a : a = Array()
		AB.Use "A"
		Set Rs = Me.db.Exec("SELECT * FROM "& s_tbPrefix & Me.Table &"")
		For i = 0 To Rs.Fields.Count-1
			f = Rs.Fields(i).Name
			a = AB.A.Push(a, f)
		Next
		Rs.Close() : Set Rs = Nothing
		tbFields = a
    End Function

	'获取数据库所有表名集合（数组）(不含表名前缀、小写)
	Public Function GetTables()
		Dim tables
		'tables = AB.C.GetTables() '自动获取数据库所有表名信息
		tables = Me.db.GetTables(Me.db.Conn)
		Dim tb, a : a = Array()
		AB.Use "A"
		For Each tb In tables
			'筛选出符合规则得表面：只能是英文+数字组合
			If AB.C.RegTest(tb, "^[a-zA-Z]\w*$") Then
				If AB.C.RegTest(tb, "^" & Me.tbPrefix & "\w+$") Then '只筛选有数据表前缀的表名
					'tb = AB.C.RP(tb, Me.tbPrefix, "")
					tb = AB.C.RegReplace(tb, "^" & Me.tbPrefix & "(\w+)$", "$1")
					tb = LCase(tb)
					a = AB.A.Push(a, tb)
				End If
			End If
		Next
		GetTables = a
    End Function

	'检测数据库是否存在某个表
	Public Function HasTable(ByVal p)
		Dim tables : AB.Use "A"
		'HasTable = Me.db.tbExists(Me.tbPrefix & p)
		tables = Me.GetTables()
		HasTable = AB.A.InArray(p, tables)
    End Function

	'按条件检索数据
	'注：此用法自由度比较高，比如要查找 id=1,3,4 这三条数据，
	'可以用：Find(Array(1,3,4))， Find("1,3,5")， Find("id in(1,3,5)") 等用法
	Public Function Find(ByVal id)
		On Error Resume Next
		Dim s_pk, s_alias, s_find, arr, Match, Matches, fields, i, j, o, b_int, f, c, v, t, a
		fields = Me.tbFields() '记录所有字段
		s_pk = Me.getPk()
		s_alias = Me.GetAlias()
		s_pk = AB.C.IIF(s_alias="", AB.C.IIF( Not(AB.C.IsNul(o_ds_join) And AB.C.IsNul(o_ds("relation"))), s_tbPrefix & Me.Table & "." & s_pk, s_pk), s_alias & "." & s_pk)
		If IsArray(id) Then '数组
			b_int = True
			For Each i In id
				If Not (AB.C.IsNum(Trim(i)) Or Trim(i)="")  Then
					b_int = False
					Exit For
				End If
			Next
			If b_int Then
				id = AB.H.Join(id, ",")
				arr = AB.A.Fetch(id,",")
				id = AB.H.Join(arr, ",")
				If Trim(id)<>"" Then s_find = s_pk & " in (" & id & ")"
			Else
				arr = Array()
				For Each i in id
					''更友好的支持格式如: Array("typeid>1", "name:jack", "email:lajox@19www.com", "workyear<=2014")
					''注：此Find方法自由度没有Where方法（自由无限制）的高，若编译生成的SQL有误，需改用 Where 方法。
					i = Trim(i) : f = "" : c = "" : v = ""
					If AB.C.RegTest(i,"^([\w\.]+)\s*(\:|\!=|[\<\>=]{1,2})\s*(['""]?)(.+)\3") Then
						Set Matches = AB.C.RegMatch(i, "^(\w+\.)\s*(\:|\!=|[\<\>=]{1,2})\s*(['""]?)(.+)\3")
						For Each Match In Matches
							f = Trim(Match.SubMatches(0))
							Select Case Match.SubMatches(1)
								Case ":", "=" : c = "="
								Case ">=" : c = ">="
								Case "<=" : c = "<="
								Case "<>", "!=" : c = "<>"
								Case ">" : c = ">"
								Case "<" : c = "<"
								Case Else : c = "="
							End Select
							v = Match.SubMatches(3)
						Next
						Set Matches = Nothing
						If Not AB.C.IsNum(v) Then '支持日期格式 如 #2014-3-20 15:06:18#
							If AB.C.RegTest(v,"^#(.+?)#$") Then
								t = AB.C.RegReplace(v,"^#(.+?)#$", "$1")
								If Not isDate(t) Then
									v = "'" & v & "'"
								End If
							Else
								v = "'" & v & "'"
							End If
						End If
					Else
						f = i : c = "" : v =""
					End If
					'If Trim(f)<>"" Then arr = AB.A.Push(arr, f & c & v)
					If Trim(f)<>"" AND (AB.A.InArray(f,fields) Or InStr(f,".")>0) Then arr = AB.A.Push(arr, f & c & v)
				Next
				''s_find = AB.H.Join(arr, " AND ") '弃用这个，为了更好的兼容下面的 And Or 模式
				s_find = "1=1"
				For Each j in arr
					If Left(LCase(Trim(j)),3) = "or " Or Left(LCase(Trim(j)),4) = "and " Then
						s_find = s_find & " " & j
					Else
						s_find = s_find & " AND " & j
					End If
				Next
			End If
		ElseIf AB.C.IsDict(id) Then '字典
			'字典数据,格式如： o_dt("name")="jack" : o_dt("typeid<")=5 : o_dt("email<>")="lajox@19www.com" : o_dt("class*")="%test%" : o_dt("class[]")=Array(1,3,5)
			arr = Array()
			For Each i In id
				i = Trim(i) : f = "" : c = "" : v = ""
				If InStr(i,"[:]")>0 Or InStr(i,":")>0 Then
					If InStr(i,"[")>0 Then f = AB.C.CLeft(i,"[") Else f = AB.C.CLeft(i,":")
					c = "="
				ElseIf InStr(i,"[>=]")>0 Or InStr(i,">=")>0 Then
					If InStr(i,"[")>0 Then f = AB.C.CLeft(i,"[") Else f = AB.C.CLeft(i,">=")
					c = ">="
				ElseIf InStr(i,"[<=]")>0 Or InStr(i,"<=")>0 Then
					If InStr(i,"[")>0 Then f = AB.C.CLeft(i,"[") Else f = AB.C.CLeft(i,"<=")
					c = "<="
				ElseIf InStr(i,"[<>]")>0 Or InStr(i,"<>")>0 Then
					If InStr(i,"[")>0 Then f = AB.C.CLeft(i,"[") Else f = AB.C.CLeft(i,"<>")
					c = "<>"
				ElseIf InStr(i,"[!=]")>0 Or InStr(i,"!=")>0 Then
					If InStr(i,"[")>0 Then f = AB.C.CLeft(i,"[") Else f = AB.C.CLeft(i,"!=")
					c = "<>"
				ElseIf InStr(i,"[=]")>0 Or InStr(i,"=")>0 Then
					If InStr(i,"[")>0 Then f = AB.C.CLeft(i,"[") Else f = AB.C.CLeft(i,"=")
					c = "="
				ElseIf InStr(i,"[>]")>0 Or InStr(i,">")>0 Then
					If InStr(i,"[")>0 Then f = AB.C.CLeft(i,"[") Else f = AB.C.CLeft(i,">")
					c = ">"
				ElseIf InStr(i,"[<]")>0 Or InStr(i,"<")>0 Then
					If InStr(i,"[")>0 Then f = AB.C.CLeft(i,"[") Else f = AB.C.CLeft(i,"<")
					c = "<"
				ElseIf InStr(i,"[like]")>0 Or InStr(i,"[%]")>0 Or InStr(i,"[*]")>0 Or InStr(i,"*")>0 Or InStr(i,"%")>0 Then '[like]或[%]或[*]或*号 匹配like
					If InStr(i,"[")>0 Then
						f = AB.C.CLeft(i,"[")
					ElseIf InStr(i,"*")>0 Then
						f = AB.C.CLeft(i,"*")
					Else
						f = AB.C.CLeft(i,"%")
					End If
					c = " LIKE "
				ElseIf InStr(i,"[in]")>0 Or InStr(i,"[]")>0 Then '[in]或[] 匹配in
					f = AB.C.CLeft(i,"[") : c = " IN "
				ElseIf i="_string" Then '自由语句
					f = "" : c = ""
				ElseIf AB.C.RegTest(Trim(i),"^[\w\.]+$") Then
					f = Trim(i) : c = "="
				Else
					f = AB.C.RP(i,Array("=",">","<","!","*","%","[like]","[in]","[","]"),"") : c = "="
				End If
				v = id(i) : f = Trim(f)
				If UCase(Trim(c)) = "IN" Or IsArray(v) Then
					If IsArray(v) Then
						a = Array()
						For Each t In v
							If AB.C.IsInt(t) Then a = AB.A.Push(a, t) Else a = AB.A.Push(a, "'"& t & "'")
						Next
						v = AB.H.Join(a, ",")
					End If
					'If Trim(f)<>"" Then arr = AB.A.Push(arr, f & " IN(" & v & ")")
					If Trim(f)<>"" AND (AB.A.InArray(f,fields) Or InStr(f,".")>0) Then arr = AB.A.Push(arr, f & " IN(" & v & ")")
				''自由语句,如 o_dt("")="id <> 6" 、o_dt("+1")="name like '%jack%'" 、 o_dt("+2")="email like '%@gmail.com%'"
				ElseIf (f="" Or Instr(f,"+")>0) And Trim(v)<>"" Then 
					arr = AB.A.Push(arr, v)
				ElseIf f = Me.getPk() And c = "="  Then '当为主键
					If Trim(f)<>"" Then arr = AB.A.Push(arr, f & " IN(" & v & ")")
				Else
					If Not AB.C.IsNum(v) Then '支持日期格式 如 #2014-3-20 15:06:18#
						If AB.C.RegTest(v,"^#(.+?)#$") Then
							t = AB.C.RegReplace(v,"^#(.+?)#$", "$1")
							If Not isDate(t) Then
								v = "'" & v & "'"
							End If
						Else
							v = "'" & v & "'"
						End If
					End If
					'If Trim(f)<>"" Then arr = AB.A.Push(arr, f & c & v)
					If Trim(f)<>"" AND (AB.A.InArray(f,fields) Or InStr(f,".")>0) Then arr = AB.A.Push(arr, f & c & v)
				End If
			Next
			s_find = "1=1"
			For Each j In arr
				If Left(LCase(Trim(j)),3) = "or " Or Left(LCase(Trim(j)),4) = "and " Then
					s_find = s_find & " " & j
				Else
					s_find = s_find & " And " & j
				End If
			Next
		ElseIf AB.C.IsNum(Trim(id)) Then '数字
			id = CLng(Trim(id))
			'If id>0 Then
				s_find = s_pk & " = " & id & ""
			'End If
		ElseIf AB.C.isStr(id) Then '字符串
			If AB.C.RegTest(Trim(id),"^([\d\,\s]+)$") Then
				arr = AB.A.Fetch(id,",")
				id = AB.H.Join(arr, ",")
				If Trim(id)<>"" Then s_find = s_pk & " in (" & id & ")"
			Else
				s_find = id
			End If
		End If
		If Trim(s_find)<>"" Then
			If AB.C.IsNul(o_ds("where")) Then
				o_ds("where") = Empty
				o_ds("where") = s_find
			Else
				If AB.C.IsDict(o_ds("where")) Then
					i_find = i_find + 1
					Set o = o_ds("where")
					o("+"& i_find) = s_find
					Set o_ds("where") = o
					Set o = Nothing
				ElseIf IsArray(o_ds("where")) Then
					o_ds("where") = AB.A.Push(o_ds("where"), s_find)
				Else
					o_ds("where") = o_ds("where") & " And " & s_find
				End If
			End If
		End If
		Set Find = Me
		On Error Goto 0
	End Function

	'获取主键字段名
	Public Function getPk()
		Dim tb, s_pk : s_pk = "id"
		tb = Trim(o_ds("table"))
		If tb<>"" Then
			If o_fs.Exists(LCase(tb)) Then
				s_pk = o_fs(LCase(tb))
			Else
				s_pk = Me.db.tbAutoID(s_tbPrefix & tb)
				o_fs(LCase(tb)) = s_pk
			End If
		End If
		getPk = s_pk
    End Function

	'返回影响的行数
	Public Function AffectedRows()
		Dim t, n : n = 0
		If b_changed = True Then
			n = i_affected
		ElseIf s_execType = 4 Or s_execType = 3 Or s_execType = 2 Then '执行Delete、Update、Insert操作
			n = Me.db.AffectedRows()
		ElseIf s_execType = -1 Then
			t = LCase(Trim(s_execSql))
			If Left(t,6)="delete" Or Left(t,6)="update" Or Left(t,6)="insert" Then
				n = Me.db.AffectedRows()
			End If
		Else
			'n = Me.db.AffectedRows()
			n = 0
		End If
		AffectedRows = n
	End Function
	Public Function affRows() : affRows = AffectedRows() : End Function

	'获取上次插入记录Id
	Public Function LastId()
		LastId = Me.db.Conn.Execute("SELECT @@IDENTITY FROM "& s_tbPrefix & Me.Table)(0)
	End Function

	'获取最大值(参数为要统计的字段名)
	Public Function Max(ByVal p)
		If AB.C.IsNul(p) Then p = Me.getPk()
		'Max = Me.db.Conn.Execute("SELECT MAX(["& p &"]) FROM "& s_tbPrefix & Me.Table)(0)
		o_ds("field") = "MAX(["& p &"])"
		Max = Me.Result()(0)
	End Function

	'获取最小值(参数为要统计的字段名)
	Public Function Min(ByVal p)
		If AB.C.IsNul(p) Then p = Me.getPk()
		'Min = Me.db.Conn.Execute("SELECT MIN(["& p &"]) FROM "& s_tbPrefix & Me.Table)(0)
		o_ds("field") = "MIN(["& p &"])"
		Min = Me.Result()(0)
	End Function

	'获取总数和(参数为要统计的字段名)
	Public Function Sum(ByVal p)
		If AB.C.IsNul(p) Then p = Me.getPk()
		'Sum = Me.db.Conn.Execute("SELECT SUM(["& p &"]) FROM "& s_tbPrefix & Me.Table)(0)
		o_ds("field") = "SUM(["& p &"])"
		Sum = Me.Result()(0)
	End Function

	'获取平均值(参数为要统计的字段名)
	Public Function Avg(ByVal p)
		If AB.C.IsNul(p) Then p = Me.getPk()
		'Avg = Me.db.Conn.Execute("SELECT AVG(["& p &"]) FROM "& s_tbPrefix & Me.Table)(0)
		o_ds("field") = "AVG(["& p &"])"
		Avg = Me.Result()(0)
	End Function

	'编译解析
	Public Sub Compile()
		Dim Matches, Match, t
		s_execSql = ""
		o_ds("table") = Trim(o_ds("table"))
		If Instr(o_ds("table")," ")>0 Then
			o_ds("table") = Trim(AB.C.CLeft(o_ds("table")," "))
			o_ds("alias") = Trim(AB.C.CRight(o_ds("table")," "))
		End If
		Select Case s_execType
			Case 1 : s_execSql = parseSql(s_selectSql, o_ds)
			Case 2 : s_execSql = parseSql(s_insertSql, o_ds)
			Case 3 : s_execSql = parseSql(s_updateSql, o_ds)
			Case 4 : s_execSql = parseSql(s_deleteSql, o_ds)
			Case Else : s_execSql = parseSql(s_querySql, "")
		End Select
		'让其支持类似{rq:id}获取App.Req("id")数据
		Set Matches = AB.C.RegMatch(s_execSql, "\{rq\:(\w+)\}")
		For Each Match In Matches
			t = Trim(Match.SubMatches(0))
			s_execSql = AB.C.RP(s_execSql, Match.Value, App.Req(t))
		Next
		'让其支持类似{$id}获取全局变量id的数据
		s_execSql = AB.C.RP(s_execSql,Array("\\","\$"),Array(Chr(15),Chr(16)))
		Set Matches = AB.C.RegMatch(s_execSql, "\{\$(\w+)\}")
		For Each Match In Matches
			t = Trim(Match.SubMatches(0))
			s_execSql = AB.C.RP(s_execSql, Match.Value, Eval(t))
		Next
		s_execSql = AB.C.RP(s_execSql,Array(Chr(15),Chr(16)),Array("\","$"))
		Set Matches = Nothing
	End Sub

	'重置数据查询（清空上次查询）
	Public Function Reset()
        o_ds.RemoveAll() : o_ds("table") = "TABLE"
        o_ds_join.RemoveAll()
		o_ds_on.RemoveAll()
		s_execType = 1
		i_join = 0
		s_querySql = ""
		i_affected = 0
		b_changed = False
		Set Reset = Me
    End Function

	Public Function Sql(ByVal s)
        If Trim(s)<>"" Then
			s_querySql = s
			s_execType = -1
		End If
		Set Sql = Me
    End Function
	
	Public Function Query(ByVal s)
        Me.Sql(s)
		Set Query = Me.Result()
    End Function

	'单数据删除数据
	Public Function Del()
		On Error Resume Next
		Del = False
		s_execType = 4
		Me.Compile()
		Me.db.Exec(s_execSql)
		''Me.Reset() '重置数据查询
		b_changed = True
		i_affected = Me.db.AffectedRows()
		If Err.Number=0 Then Del = True
		On Error Goto 0
    End Function

	'批量数据删除, 支持数组，字符串，数字
	'注：此用法自由度比较高，比如要删除 id=1,3,4 这三条数据，
	'可以用：Delete(Array(1,3,4))， Delete("1,3,5")， Delete("id in(1,3,5)") 等用法
	Public Function Delete(ByVal id)
		On Error Resume Next
		Delete = False
		If Not AB.C.IsNul(id) Then
			Me.Find(id)
			s_execType = 4
			Me.Compile()
			Me.db.Exec(s_execSql)
			''Me.Reset() '重置数据查询
			b_changed = True
			i_affected = Me.db.AffectedRows()
			If Err.Number=0 Then Delete = True
		End If
		On Error Goto 0
	End Function

	'更新数据
	Public Function [Set](ByVal d)
		On Error Resume Next
		[Set] = False
		Dim Rs, i, f, v, n, fields, pk : n = 0
		Dim b_up : b_up = 0
		If AB.C.IsNul(d) Then
			[Set] = False
			i_affected = 0
			Exit Function
		End If
		Set Rs = Me.Result()
		pk = Me.getPk()
		fields = Me.RsFields(Rs)
		fields = AB.A.Del(fields, pk) '移除自增主键
		n = Me.RsCount(Rs)
		Do While Not Rs.Eof
			If AB.C.IsDict(d) Then
				For Each i In d
					If Not (AB.A.InArray(i,fields) Or InStr(i,".")>0) Then
						d.Remove(i)
					End If
				Next
				For Each i In d
					If (AB.A.InArray(i,fields) Or InStr(i,".")>0) Then
						v = d(i)
						If AB.C.IsNum(v) Then v = CLng(v)
						If (Rs.Fields(i).Type=7 Or Rs.Fields(i).Type=135) Then '日期时间
							If AB.C.isNul(v) Then
								Rs.Fields.Item(i) = Null '设置为空值
							ElseIf AB.C.RegTest(Trim(v),"^#.+#$") Then
								Rs.Fields.Item(i) = Eval(Trim(v))
							Else
								Rs.Fields.Item(i) = CDate(v)
							End If
						Else
							Rs.Fields.Item(i) = v
						End If
					End If
				Next
			ElseIf IsArray(d) Then '数组，格式: Array("typeid:1", "name:jack", "workyear:2014")
				For Each i In d
					f = AB.C.CLeft(i,":")
					v = AB.C.CRight(i,":")
					If AB.C.IsNum(v) Then v = CLng(v)
					If (AB.A.InArray(f,fields) Or InStr(f,".")>0) Then
						If (Rs.Fields(f).Type=7 Or Rs.Fields(f).Type=135) Then '日期时间
							If AB.C.isNul(v) Then
								Rs.Fields.Item(f) = Null '设置为空值
							ElseIf AB.C.RegTest(Trim(v),"^#.+#$") Then
								Rs.Fields.Item(f) = Eval(Trim(v))
							Else
								Rs.Fields.Item(f) = CDate(v)
							End If
						Else
							Rs.Fields.Item(f) = v
						End If
					End If
				Next
			ElseIf IsObject(d) And (TypeName(d)="IRequestDictionary" Or TypeName(d)="IRequest" Or TypeName(d)="Object") Then '整个表单数据
				AB.Use "Form"
				IF AB.Form.Count>0 Then
					For Each i In AB.Form.Items
						If (AB.A.InArray(i,fields) Or InStr(i,".")>0) Then
							v = AB.Form.Item(i)
							If AB.C.IsNum(v) Then v = CLng(v)
							If (Rs.Fields(i).Type=7 Or Rs.Fields(i).Type=135) Then '日期时间
								If AB.C.isNul(v) Then
									Rs.Fields.Item(i) = Null '设置为空值
								ElseIf AB.C.RegTest(Trim(v),"^#.+#$") Then
									Rs.Fields.Item(i) = Eval(Trim(v))
								Else
									Rs.Fields.Item(i) = CDate(v)
								End If
							Else
								Rs.Fields.Item(i) = v
							End If
						End If
					Next
				End IF
			ElseIf AB.C.isStr(d) Then '字符串，格式："typeid:1"
				f = AB.C.CLeft(d,":")
				v = AB.C.CRight(d,":")
				If AB.C.IsNum(v) Then v = CLng(v)
				If (AB.A.InArray(f,fields) Or InStr(f,".")>0) Then
					If (Rs.Fields(f).Type=7 Or Rs.Fields(f).Type=135) Then '日期时间
						If AB.C.isNul(v) Then
							Rs.Fields.Item(f) = Null '设置为空值
						ElseIf AB.C.RegTest(Trim(v),"^#.+#$") Then
							Rs.Fields.Item(f) = Eval(Trim(v))
						Else
							Rs.Fields.Item(f) = CDate(v)
						End If
					Else
						Rs.Fields.Item(f) = v
					End If
				End If
			Else
				b_up = 1
				Exit Do
			End If
			Rs.Update()
			If Not Rs.Eof Then Rs.MoveNext
		Loop
		Rs.Close() : Set Rs = Nothing
		b_changed = True
		If Err.Number=0 And b_up=0 Then
			[Set] = True
			i_affected = n
		Else
			i_affected = 0
		End If
		On Error Goto 0
    End Function

	Public Function Update(ByVal d)
        Update = [Set](d)
    End Function

	Public Function Edit(ByVal d)
        Edit = [Set](d)
    End Function

	'更新字段
	Public Function setField(ByVal k, ByVal v)
		On Error Resume Next
		setField = False
		Dim Rs, i, j, t, n, fields, f : n = 0 : b_changed = False
		If AB.C.IsNul(k) Then
			setField = False
			i_affected = 0
			Exit Function
		End If
		Set Rs = Me.Result()
		fields = Me.RsFields(Rs)
		n = Me.RsCount(Rs)
		If n > 0 Then
			Do While Not Rs.Eof
				If IsArray(k) Then
					t = v
					For i=0 To UBound(k)
						If IsArray(v) Then
							If UBound(v)>=UBound(k) Then
								t = v(i)
							Else
								If i<=UBound(v) Then
									t = v(i)
								Else
									t = ""
								End If
							End If
						End If
						If (AB.A.InArray(k(i),fields) Or InStr(k(i),".")>0) Then
							f = k(i)
							If (Rs.Fields(f).Type=7 Or Rs.Fields(f).Type=135) Then '日期时间
								If AB.C.isNul(t) Then
									Rs.Fields.Item(f) = Null '设置为空值
								ElseIf AB.C.RegTest(Trim(t),"^#.+#$") Then
									Rs.Fields.Item(f) = Eval(Trim(t))
								Else
									Rs.Fields.Item(f) = CDate(t)
								End If
							Else
								Rs.Fields.Item(f) = t
							End If
						End If
					Next
				Else
					If (AB.A.InArray(k,fields) Or InStr(k,".")>0) Then
						f = k
						If (Rs.Fields(f).Type=7 Or Rs.Fields(f).Type=135) Then '日期时间
							If AB.C.isNul(v) Then
								Rs.Fields.Item(f) = Null '设置为空值
							ElseIf AB.C.RegTest(Trim(v),"^#.+#$") Then
								Rs.Fields.Item(f) = Eval(Trim(v))
							Else
								Rs.Fields.Item(f) = CDate(v)
							End If
						Else
							Rs.Fields.Item(f) = v
						End If
					End If
				End If
				Rs.Update()
				If Not Rs.Eof Then Rs.MoveNext
			Loop
		End If
		Rs.Close() : Set Rs = Nothing
		b_changed = True
		If Err.Number=0 Then
			setField = True
			i_affected = 1
		Else
			i_affected = 0
		End If
		On Error Goto 0
    End Function

	'字段值增长
	Public Function setInc(ByVal k, ByVal v)
		On Error Resume Next
		setInc = False
		Dim Rs, i, j, t, fields : b_changed = False
		If AB.C.IsNul(k) Then
			setInc = False
			i_affected = 0
			Exit Function
		End If
		Set Rs = Me.Result()
		fields = Me.RsFields(Rs)
		If (AB.A.InArray(k,fields) Or InStr(k,".")>0) Then
			If AB.C.IsNul(Rs(k).Value) Then Rs(k) = 0
			Rs(k) = Rs(k) + v
		End If
		Rs.Update()
		Rs.Close() : Set Rs = Nothing
		b_changed = True
		If Err.Number=0 Then
			setInc = True
			i_affected = 1
		Else
			i_affected = 0
		End If
		On Error Goto 0
    End Function

	'字段值减小
	Public Function setDec(ByVal k, ByVal v)
		On Error Resume Next
		setDec = False
		Dim Rs, i, j, t, fields : b_changed = False
		If AB.C.IsNul(k) Then
			setDec = False
			i_affected = 0
			Exit Function
		End If
		Set Rs = Me.Result()
		fields = Me.RsFields(Rs)
		If (AB.A.InArray(k,fields) Or InStr(k,".")>0) Then
			If AB.C.IsNul(Rs(k).Value) Then Rs(k) = 0
			Rs(k) = Rs(k) - v
		End If
		Rs.Update()
		Rs.Close() : Set Rs = Nothing
		b_changed = True
		If Err.Number=0 Then
			setDec = True
			i_affected = 1
		Else
			i_affected = 0
		End If
		On Error Goto 0
    End Function

	'添加数据
	Public Function Add(ByVal d)
		On Error Resume Next
		Add = False
		Dim Rs, i, f, v, fields, pk : b_changed = False
		If AB.C.IsNul(d) Then
			Add = False
			Exit Function
		End If
		AB.Use "A"
		Set Rs = Me.Result()
		pk = Me.getPk()
		fields = Me.RsFields(Rs)
		fields = AB.A.Del(fields, pk) '移除自增主键
		Rs.AddNew()
		If AB.C.IsDict(d) Then
			For Each i In d
				If Not (AB.A.InArray(i,fields) Or InStr(i,".")>0) Then
					d.Remove(i)
				End If
			Next
			For Each i In d
				If (AB.A.InArray(i,fields) Or InStr(i,".")>0) Then
					v = d(i)
					If AB.C.IsNum(v) Then v = CLng(v)
					If (Rs.Fields(i).Type=7 Or Rs.Fields(i).Type=135) Then '日期时间
						If AB.C.isNul(v) Then
							Rs.Fields.Item(i) = Null '设置为空值
						ElseIf AB.C.RegTest(Trim(v),"^#.+#$") Then
							Rs.Fields.Item(i) = Eval(Trim(v))
						Else
							Rs.Fields.Item(i) = CDate(v)
						End If
					Else
						Rs.Fields.Item(i) = v
					End If
				End If
			Next
			b_changed = True
		ElseIf IsArray(d) Then '数组，格式: Array("typeid:1", "name:jack", "workyear:2014")
			For Each i In d
				f = AB.C.CLeft(i,":")
				v = AB.C.CRight(i,":")
				If AB.C.IsNum(v) Then v = CLng(v)
				If (AB.A.InArray(f,fields) Or InStr(f,".")>0) Then
					If (Rs.Fields(f).Type=7 Or Rs.Fields(f).Type=135) Then '日期时间
						If AB.C.isNul(v) Then
							Rs.Fields.Item(f) = Null '设置为空值
						ElseIf AB.C.RegTest(Trim(v),"^#.+#$") Then
							Rs.Fields.Item(f) = Eval(Trim(v))
						Else
							Rs.Fields.Item(f) = CDate(v)
						End If
					Else
						Rs.Fields.Item(f) = v
					End If
				End If
			Next
			b_changed = True
		ElseIf IsObject(d) And (TypeName(d)="IRequestDictionary" Or TypeName(d)="IRequest" Or TypeName(d)="Object") Then '整个表单数据
			AB.Use "Form"
			IF AB.Form.Count>0 Then
				For Each i In AB.Form.Items
					If (AB.A.InArray(i,fields) Or InStr(i,".")>0) Then
						v = AB.Form.Item(i)
						If AB.C.IsNum(v) Then v = CLng(v)
						If (Rs.Fields(i).Type=7 Or Rs.Fields(i).Type=135) Then '日期时间
							If AB.C.isNul(v) Then
								Rs.Fields.Item(i) = Null '设置为空值
							ElseIf AB.C.RegTest(Trim(v),"^#.+#$") Then
								Rs.Fields.Item(i) = Eval(Trim(v))
							Else
								Rs.Fields.Item(i) = CDate(v)
							End If
						Else
							Rs.Fields.Item(i) = v
						End If
					End If
				Next
			End IF
			b_changed = True
		ElseIf AB.C.isStr(d) Then '字符串，格式："typeid:1"
			f = AB.C.CLeft(d,":")
			v = AB.C.CRight(d,":")
			If AB.C.IsNum(v) Then v = CLng(v)
			If (AB.A.InArray(f,fields) Or InStr(f,".")>0) Then
				If (Rs.Fields(f).Type=7 Or Rs.Fields(f).Type=135) Then '日期时间
					If AB.C.isNul(v) Then
						Rs.Fields.Item(f) = Null '设置为空值
					ElseIf AB.C.RegTest(Trim(v),"^#.+#$") Then
						Rs.Fields.Item(f) = Eval(Trim(v))
					Else
						Rs.Fields.Item(f) = CDate(v)
					End If
				Else
					Rs.Fields.Item(f) = v
				End If
			End If
			b_changed = True
		Else
			b_changed = False
		End If
		Rs.Update()
		Rs.Close() : Set Rs = Nothing
		If Err.Number=0 Then
			Add = True
			i_affected = 1
		Else
			i_affected = 0
		End If
		On Error Goto 0
    End Function

	'保存数据（智能更新或添加数据）
	Public Function Save(ByVal d)
		On Error Resume Next
		Dim Rs : Save = False
		If Not AB.C.IsNul(o_ds("where")) Or Not AB.C.IsNul(o_ds("top")) Then
			Set Rs = Me.Result()
			If Not (Rs.Eof Or Rs.Bof) Then
				Save = Me.Update(d)
			End If
		Else
			Save = Me.Add(d)
		End If
		On Error Goto 0
    End Function

	Public Function getSQL()
		Me.Compile() '自编译
        getSQL = s_execSql
    End Function
	Public Function buildSQL() : buildSQL = Me.getSQL() : End Function
	Public Function lastSQL() : lastSQL = Me.getSQL() : End Function

	'执行SQL语句操作
	Public Function [Execute](ByVal sql)
		Me.Sql(sql)
		Me.Compile() '自编译
		Me.db.Exec(s_execSql)
		''Me.Reset()	'重置数据查询
	End Function

	'执行
	Public Function Exec()
		Me.Compile() '自编译
		Me.db.Exec(s_execSql)
		''Me.Reset()	'重置数据查询
	End Function

	'获取数据列表(数组数据)
	'Dim arrRs : arrRs = App.Dao.Select("id,name").Where("id<10").List() : AB.Trace arrRs
	Public Function List()
		Me.Compile() '自编译
        List = Me.db.Run(s_execSql,"arr")
		''Me.Reset()	'重置数据查询
    End Function
	
	'获取Rs结果集
	Public Function Result()
		On Error Resume Next
		Me.Compile() '自编译
		''Set Result = Me.db.GRS(s_execSql) '只读
		'Set Result = Me.db.Exec(s_execSql) '可读写
		Set Result = Me.db.Run(s_execSql,"rst3") '可读写
		''Me.Reset()	'重置数据查询
		If o_ds.Exists("offset") Or o_ds.Exists("rows") Then
			Dim offset, rows, start, over, n, i
			offset = CLng(o_ds("offset"))
			rows = CLng(o_ds("rows"))
			Set Result = Me.LimitRs(Result,offset,rows)
		End If
		On Error Goto 0
    End Function
	Public Function GetRs() : Set GetRs = Me.Result() : End Function

	'取Rs结果集
	Public Function Fetch()
		Set Fetch = Me.Result()
	End Function
	Public Function FetchRs() : Set FetchRs = Me.Result() : End Function

	'取第一行单条Rs数据
	Public Function FetchOne()
		Me.Top(1)
		Set FetchOne = Me.Result()
	End Function
	Public Function One() : Set One = Me.FetchOne() : End Function

	'取数据列表(数组数据)
	Public Function FetchArray()
		FetchArray = Me.List()
	End Function

	'获取Rs结果集中的第n+1行单条数据(n为偏移量)
	Public Function FetchRow(ByVal n)
		On Error Resume Next
		n = CLng(n)
		If n<0 Then n=0
		Set FetchRow = Me.Result()
		' If Not Rs.Eof Then
			' FetchRow.Move(n)
		' End If
		Set FetchRow = Me.LimitRs(FetchRow,n,1)
		On Error Goto 0
	End Function
	Public Function Row(ByVal n) : Set Row = Me.FetchRow(n) : End Function

	'取得Rs的记录数
	Public Function RsCount(ByVal Rs)
		Dim n : n = 0
		If AB.C.IsRs(Rs) Then
			n = Rs.RecordCount
			If n=-1 Then
				n = Ubound(Rs.GetRows(),2)+1
			End If
		End If
		RsCount = n
    End Function

	'获取数据条数
	Public Function Count()
		On Error Resume Next
		Dim c, Rs : c = 0
		Set Rs = Me.Result()
		If Not Rs.Eof Then c = Me.RsCount(Rs)
		Rs.Close() : Set Rs = Nothing
		Count = c
		On Error Goto 0
    End Function

	'获取字段信息组数
	Public Function FieldsData()
		On Error Resume Next
		Dim item, tRs, arr : arr = Array()
		Set tRs = Me.Result()
		For Each item In tRs.Fields
			arr = AB.A.Push(arr, item.name)
		Next
		tRs.Close() : Set tRs = Nothing
		FieldsData = arr
		On Error Goto 0
    End Function

	'获取字段数
	Public Function FieldsCount()
		Dim arr : arr = Me.FieldsData()
		FieldsCount = AB.A.Len(arr)
    End Function
	Public Function FieldsNum()
		FieldsNum = Me.FieldsCount()
    End Function

	'克隆Rs数据集
	Public Function CloneRs(ByVal Rs)
		On Error Resume Next
		Set CloneRs = Me.db.CloneRs(Rs)
		On Error Goto 0
	End Function

	'对Rs结果集进行Limit限制
	Public Function LimitRs(ByVal Rs, ByVal offset, ByVal rows)
		On Error Resume Next
		Dim tRs, newRs, start, over, n, i, j, f, v, a, b
		offset = CLng(offset) : rows = CLng(rows)
		If AB.C.isRs(Rs) Then
			Set LimitRs = Rs
			If Not ( AB.C.IsNul(Rs) Or (offset<=0 And rows<=0) ) Then
				If offset<0 Then offset=0
				If rows<0 Then rows=0
				n = Me.RsCount(Rs) 'Rs记录数
				If rows=0 Then rows = n
				start = offset + 1
				over = offset + rows
				If over>n Then over = n
				If Me.RsCount(Rs)>0 Then '采用这种写法，效率最高
					Set tRs = Me.CloneRs(Rs)
					Set newRs = AB.C.NewRs()
					newRs.CursorLocation = 1
					newRs.CursorType = 3
					For i = 0 To tRs.Fields.Count-1
						newRs.Fields.Append tRs.Fields(i).Name, tRs.Fields(i).Type, tRs.Fields(i).DefinedSize, tRs.Fields(i).Attributes
					Next
					newRs.Open
					i = 1
					tRs.Move(start-1)
					Do While Not tRs.Eof
						i = i + 1
						a = Array()
						b = Array()
						For j = 0 To tRs.Fields.Count-1
							f = tRs.Fields(j).Name
							v = tRs.Fields(j).Value
							If Not AB.A.InArray(tRs.Fields(j).Type, Array( 7, 135 )) Then
								'v = AB.C.IIF(AB.C.isNul(v),"",v)
							End If
							a = AB.A.Push(a, f)
							b = AB.A.Push(b, v)
						Next
						newRs.AddNew a, b
						newRs.Update()
						tRs.MoveNext
						If i>rows Then Exit Do
					Loop
					tRs.Close() : Set tRs = Nothing
					If Me.RsCount(newRs)>0 Then newRs.MoveFirst()
					Set LimitRs = newRs
				Else '屏蔽下面写法，因数据量大导致查询很慢。
					Set LimitRs = Me.CloneRs(Rs)
					i = 1
					If start>n Then
						Do While Not LimitRs.Eof
							i = i + 1
							LimitRs.Delete
							LimitRs.MoveNext
						Loop
						If i > 1 Then
							LimitRs.UpdateBatch()
							LimitRs.MoveFirst()
						End If
					Else
						Do While Not LimitRs.Eof
							If i<start Then LimitRs.Delete
							If i>over Then LimitRs.Delete
							i = i + 1
							LimitRs.MoveNext
						Loop
						If i > 1 Then
							LimitRs.UpdateBatch()
							If Me.RsCount(LimitRs) > 0 Then LimitRs.MoveFirst()
						End If
					End If
				End If
			End If
		Else
			If IsObject(Rs) Then Set LimitRs = Rs Else LimitRs = Rs
		End If
		On Error Goto 0
    End Function

	'对Rs数据集应用Sort排序
	Public Function SortRs(ByVal Rs, ByVal sort)
		On Error Resume Next
		Set SortRs = Me.db.SortRs(Rs,sort)
		On Error Goto 0
	End Function

    '-- 替换SQL语句中表达式
	Private Function parseSql(ByVal sql, ByVal opt)
		sql = AB.C.RP(sql, Array("\\","\@"), Array(Chr(17),Chr(18)))
		sql = AB.C.RP(sql, "#@", s_tbPrefix)
		sql = AB.C.RP(sql, Array(Chr(17),Chr(18)), Array("\","@"))
		If AB.C.IsDict(opt) Then
			If Not AB.C.IsNul(opt("relation")) Then
				sql = AB.C.RP(sql, "%JOINON%", parseRelation(opt("relation")))
			End If
			sql = AB.C.RP(sql, _
				array("%TABLE%","%ALIAS%","%FIELD%","%TOP%","%JOINON%","%WHERE%","%GROUP%","%HAVING%","%ORDER%","%UNION%"), _
				array( _
					parseTable(AB.C.IIF(Not(AB.C.isNul(opt("table"))), s_tbPrefix & opt("table"), "TABLE")), _
					parseAlias(AB.C.IIF(Not(AB.C.isNul(opt("alias"))), opt("alias"), "")), _
					parseField(AB.C.IIF(Not(AB.C.isNul(opt("field"))), opt("field"), "*")), _
					parseTop(AB.C.IIF(Not(AB.C.isNul(opt("top"))), AB.C.IIF(CLng(opt("top"))>0, opt("top"), ""), "")), _
					parseJoinOn(o_ds_join, o_ds_on), _
					parseWhere(AB.C.IIF(Not(AB.C.isNul(opt("where"))), opt("where"), "")), _
					parseGroup(AB.C.IIF(Not(AB.C.isNul(opt("group"))), opt("group"), "")), _
					parseHaving(AB.C.IIF(Not(AB.C.isNul(opt("having"))), opt("having"), "")), _
					parseOrder(AB.C.IIF(Not(AB.C.isNul(opt("order"))), opt("order"), "")), _
					parseUnion(AB.C.IIF(Not(AB.C.isNul(opt("union"))), opt("union"), "")) _
				))
		End If
		parseSql = sql
    End Function
	
    '-- table分析
	Private Function parseTable(ByVal tables)
		Dim arr : arr = Array()
        If Not AB.C.IsNul(tables) Then
            If IsArray(tables) Then
				For Each j in tables
					arr = AB.A.Push(arr, j)
				Next
				tables = AB.H.Join(arr, ", ")
            End If
        End If
		If AB.C.IsNul(tables) Then tables = ""
		parseTable = tables
    End Function

    '-- 表别名Alias分析
	'e.g. parseAlias("a.cid = b.cid")
    Private Function parseAlias(ByVal str)
		If Not AB.C.IsNul(str) Then
			str = " " & str
		Else
			str = ""
		End If
		str = ReplaceTable(str)
		parseAlias = str
    End Function

    '-- field分析
	Private Function parseField(ByVal field)
		Dim a, i
		If Not AB.C.IsNul(field) Then
			If IsArray(field) Then
				a = Array()
				For Each i In a
					If Trim(i)<>"" Then a = AB.A.Push(a,i)
				Next
				field = Join(a, ",")
			End If
			If Trim(field)="" Then field = "*"
		Else
			field = "*"
		End If
		field = ReplaceTable(field)
		field = AB.C.RP(field, "#@", s_tbPrefix) '替换数据表前缀
		parseField = field
    End Function

    '-- where分析
	Private Function parseWhere(ByVal where)
		Dim s_where, arr, Match, Matches, fields, i, j, f, v, c, t, a
		fields = Me.tbFields() '记录所有字段
		If Not AB.C.isNul(where) Then
			If IsArray(where) Then '数组
				arr = Array()
				For Each i in where
					If Trim(i)<>"" Then arr = AB.A.Push(arr, i)
				Next
				''where = AB.H.Join(arr, " And ") '弃用这个，为了更好的兼容下面的 And Or 模式
				s_where = "1=1"
				For Each j in arr
					If Left(LCase(Trim(j)),3) = "or " Or Left(LCase(Trim(j)),4) = "and " Then
						s_where = s_where & " " & j
					Else
						s_where = s_where & " And " & j
					End If
				Next
			ElseIf AB.C.IsDict(where) Then
				'字典数据,格式如： o_ds("name")="jack" : o_ds("typeid<")=5 : o_ds("email<>")="lajox@19www.com" : o_ds("class*")="%test%" : o_ds("class[]")=Array(1,3,5)
				arr = Array()
				For Each i In where
					i = Trim(i) : f = "" : c = "" : v = ""
					If InStr(i,"[:]")>0 Or InStr(i,":")>0 Then
						If InStr(i,"[")>0 Then f = AB.C.CLeft(i,"[") Else f = AB.C.CLeft(i,":")
						c = "="
					ElseIf InStr(i,"[>=]")>0 Or InStr(i,">=")>0 Then
						If InStr(i,"[")>0 Then f = AB.C.CLeft(i,"[") Else f = AB.C.CLeft(i,">=")
						c = ">="
					ElseIf InStr(i,"[<=]")>0 Or InStr(i,"<=")>0 Then
						If InStr(i,"[")>0 Then f = AB.C.CLeft(i,"[") Else f = AB.C.CLeft(i,"<=")
						c = "<="
					ElseIf InStr(i,"[<>]")>0 Or InStr(i,"<>")>0 Then
						If InStr(i,"[")>0 Then f = AB.C.CLeft(i,"[") Else f = AB.C.CLeft(i,"<>")
						c = "<>"
					ElseIf InStr(i,"[!=]")>0 Or InStr(i,"!=")>0 Then
						If InStr(i,"[")>0 Then f = AB.C.CLeft(i,"[") Else f = AB.C.CLeft(i,"!=")
						c = "<>"
					ElseIf InStr(i,"[=]")>0 Or InStr(i,"=")>0 Then
						If InStr(i,"[")>0 Then f = AB.C.CLeft(i,"[") Else f = AB.C.CLeft(i,"=")
						c = "="
					ElseIf InStr(i,"[>]")>0 Or InStr(i,">")>0 Then
						If InStr(i,"[")>0 Then f = AB.C.CLeft(i,"[") Else f = AB.C.CLeft(i,">")
						c = ">"
					ElseIf InStr(i,"[<]")>0 Or InStr(i,"<")>0 Then
						If InStr(i,"[")>0 Then f = AB.C.CLeft(i,"[") Else f = AB.C.CLeft(i,"<")
						c = "<"
					ElseIf InStr(i,"[like]")>0 Or InStr(i,"[%]")>0 Or InStr(i,"[*]")>0 Or InStr(i,"*")>0 Or InStr(i,"%")>0 Then '[like]或[%]或[*]或*号 匹配like
						If InStr(i,"[")>0 Then
							f = AB.C.CLeft(i,"[")
						ElseIf InStr(i,"*")>0 Then
							f = AB.C.CLeft(i,"*")
						Else
							f = AB.C.CLeft(i,"%")
						End If
						c = " LIKE "
					ElseIf InStr(i,"[in]")>0 Or InStr(i,"[]")>0 Then '[in]或[] 匹配in
						f = AB.C.CLeft(i,"[") : c = " IN "
					ElseIf i="_string" Then '自由语句
						f = "" : c = ""
					ElseIf AB.C.RegTest(Trim(i),"^[\w\.]+$") Then
						f = Trim(i) : c = "="
					Else
						f = AB.C.RP(i,Array("=",">","<","!","*","%","[like]","[in]","[","]"),"") : c = "="
					End If
					v = where(i) : f = Trim(f)
					If UCase(Trim(c)) = "IN" Or IsArray(v) Then
						If IsArray(v) Then
							a = Array()
							For Each t In v
								If AB.C.IsInt(t) Then a = AB.A.Push(a, t) Else a = AB.A.Push(a, "'"& t & "'")
							Next
							v = AB.H.Join(a, ",")
						End If
						'If Trim(f)<>"" Then arr = AB.A.Push(arr, f & " IN(" & v & ")")
						If Trim(f)<>"" AND (AB.A.InArray(f,fields) Or InStr(f,".")>0) Then arr = AB.A.Push(arr, f & " IN(" & v & ")")
					''自由语句,如 o_ds("")="id <> 6" 、o_ds("+1")="name like '%jack%'" 、 o_ds("+2")="email like '%@gmail.com%'"
					ElseIf (f="" Or Instr(f,"+")>0 Or f="_string") And Trim(v)<>"" Then 
						arr = AB.A.Push(arr, v)
					ElseIf f = Me.getPk() And c = "="  Then '当为主键
						If Trim(f)<>"" Then arr = AB.A.Push(arr, f & " IN(" & v & ")")
					Else
						If Not AB.C.IsNum(v) Then
							If AB.C.RegTest(v,"^#(.+?)#$") Then
								t = AB.C.RegReplace(v,"^#(.+?)#$", "$1")
								If Not isDate(t) Then
									v = "'" & v & "'"
								End If
							Else
								v = "'" & v & "'"
							End If
						End If
						'If Trim(f)<>"" Then arr = AB.A.Push(arr, f & c & v)
						If Trim(f)<>"" AND (AB.A.InArray(f,fields) Or InStr(f,".")>0) Then arr = AB.A.Push(arr, f & c & v)
					End If
				Next
				s_where = "1=1"
				For Each j In arr
					If Left(LCase(Trim(j)),3) = "or " Or Left(LCase(Trim(j)),4) = "and " Then
						s_where = s_where & " " & j
					Else
						s_where = s_where & " And " & j
					End If
				Next
			Else '字符串
				s_where = where
			End If
			If Trim(s_where)<>"" Then
				where = " WHERE "& s_where
			End If
		Else
			where = ""
		End If
		where = ReplaceTable(where)
		parseWhere = where
    End Function

    '-- top分析
	Private Function parseTop(ByVal top)
		On Error Resume Next
		If Trim(top)<>"" Then
			If Instr(Lcase(top),"top ")>0 Then
				top = UCase(top)
			Else
				If CLng(top)>0 Then top = " TOP " & top
			End If
		Else
			top = ""
		End If
		parseTop = top
		On Error Goto 0
    End Function
	
    Private Function parseRelation(ByVal rel)
		On Error Resume Next
		Dim str, table, condi
		If AB.C.IsDict(rel) Then
			table = rel("table")
			If Not rel.Exists("auto_prefix") Or AB.C.IsNul(rel("auto_prefix")) Or LCase(rel("auto_prefix"))="true" Then
				table = s_tbPrefix & table
			End If
			condi = rel("condition")
			condi = AB.C.RP(condi, "#@", s_tbPrefix) '替换数据表前缀
			str = " LEFT JOIN " & table & " ON " & condi
		ElseIf IsArray(rel) Then
			table = rel(0)
			If AB.A.Len(rel)>2 Then
				If AB.C.IsNul(rel(2)) Or LCase(rel(2))="true" Then
					table = s_tbPrefix & table
				End If
			End If
			condi = rel(1)
			condi = AB.C.RP(condi, "#@", s_tbPrefix) '替换数据表前缀
			str = " LEFT JOIN " & table & " ON " & condi
		End If
		parseRelation = str
		On Error Goto 0
    End Function

    '-- join on分析，可多次JOIN和ON
	'e.g. parseJoinOn("join __TEST__", "a.cid = b.pid")
    Private Function parseJoinOn(ByVal o_join, ByVal o_on)
		Dim i, j, jstr, ostr, fstr, a : a = Array()
		AB.Use "A"
        If Not AB.C.IsNul(o_join) Then
			For i = 1 To i_join
				jstr = "" : ostr = ""
				If IsArray(o_join(i)) Then
					For Each j in o_join(i)
						If AB.C.RegTest(Lcase(j), "^\s*join\s+") Then
							jstr = jstr & " " & AB.C.RegReplace(j, "^\s*join\s+", "JOIN ")
						ElseIf AB.C.RegTest(Lcase(j), "^\s*left\s+join\s+") Then
							jstr = jstr & " " & AB.C.RegReplace(j, "^\s*left\s+join\s+", "LEFT JOIN ")
						ElseIf AB.C.RegTest(Lcase(j), "^\s*right\s+join\s+") Then
							jstr = jstr & " " & AB.C.RegReplace(j, "^\s*right\s+join\s+", "RIGHT JOIN ")
						ElseIf AB.C.RegTest(Lcase(j), "^\s*inner\s+join\s+") Then
							jstr = jstr & " " & AB.C.RegReplace(j, "^\s*inner\s+join\s+", "INNER JOIN ")
						ElseIf AB.C.RegTest(Lcase(j), "^\s*outer\s+join\s+") Then
							jstr = jstr & " " & AB.C.RegReplace(j, "^\s*outer\s+join\s+", "OUTER JOIN ")
						ElseIf AB.C.RegTest(Lcase(j), "^\s*left\s+outer\s+join\s+") Then
							jstr = jstr & " " & AB.C.RegReplace(j, "^\s*left\s+outer\s+join\s+", "LEFT OUTER JOIN ")
						ElseIf AB.C.RegTest(Lcase(j), "^\s*right\s+outer\s+join\s+") Then
							jstr = jstr & " " & AB.C.RegReplace(j, "^\s*right\s+outer\s+join\s+", "RIGHT OUTER JOIN ")
						Else
							jstr = jstr & " LEFT JOIN " & j
						End If
					Next
				Else
					If AB.C.RegTest(Lcase(o_join(i)), "^\s*join\s+") Then
						jstr = jstr & " " & AB.C.RegReplace(o_join(i), "^\s*join\s+", "JOIN ")
					ElseIf AB.C.RegTest(Lcase(o_join(i)), "^\s*left\s+join\s+") Then
						jstr = jstr & " " & AB.C.RegReplace(o_join(i), "^\s*left\s+join\s+", "LEFT JOIN ")
					ElseIf AB.C.RegTest(Lcase(o_join(i)), "^\s*right\s+join\s+") Then
						jstr = jstr & " " & AB.C.RegReplace(o_join(i), "^\s*right\s+join\s+", "RIGHT JOIN ")
					ElseIf AB.C.RegTest(Lcase(o_join(i)), "^\s*inner\s+join\s+") Then
						jstr = jstr & " " & AB.C.RegReplace(o_join(i), "^\s*inner\s+join\s+", "INNER JOIN ")
					ElseIf AB.C.RegTest(Lcase(o_join(i)), "^\s*outer\s+join\s+") Then
						jstr = jstr & " " & AB.C.RegReplace(o_join(i), "^\s*outer\s+join\s+", "OUTER JOIN ")
					ElseIf AB.C.RegTest(Lcase(o_join(i)), "^\s*left\s+outer\s+join\s+") Then
						jstr = jstr & " " & AB.C.RegReplace(o_join(i), "^\s*left\s+outer\s+join\s+", "LEFT OUTER JOIN ")
					ElseIf AB.C.RegTest(Lcase(o_join(i)), "^\s*right\s+outer\s+join\s+") Then
						jstr = jstr & " " & AB.C.RegReplace(o_join(i), "^\s*right\s+outer\s+join\s+", "RIGHT OUTER JOIN ")
					Else
						jstr = jstr & " LEFT JOIN " & o_join(i)
					End If
				End If
				If IsArray(o_on(i)) Then
					For Each j in o_on(i)
						ostr = ostr & "ON " & j
					Next
				Else
					ostr = ostr & "ON " & o_on(i)
				End If
				a = AB.A.Push(a, jstr & " " & ostr)
			Next
        End If
		fstr = AB.H.Join(a, " ")
		fstr = ReplaceTable(fstr)
		fstr = AB.C.RP(fstr, "#@", s_tbPrefix) '替换数据表前缀
        parseJoinOn = fstr
    End Function

    '-- order分析
	'e.g. parseOrder("listnum desc, id asc")
    Private Function parseOrder(ByVal order)
		If IsArray(order) Then
			Dim j, arr : arr = Array()
			For Each j in order
				arr = AB.A.Push(arr, j)
			Next
			order = AB.H.Join(arr, ", ")
		End If
		If Not AB.C.IsNul(order) Then
			order = " ORDER BY " & order
		Else
			order = ""
		End If
		order = ReplaceTable(order)
		parseOrder = order
    End Function

    '-- group分析
	'e.g. parseGroup("name")
    Private Function parseGroup(ByVal group)
		Dim j, arr : arr = Array()
		If IsArray(group) Then
			For Each j in group
				arr = AB.A.Push(arr, j)
			Next
			group = AB.H.Join(arr, ", ")
		End If
		If Not AB.C.IsNul(group) Then
			group = " GROUP BY " & group
		Else
			group = ""
		End If
		group = ReplaceTable(group)
		parseGroup = group
    End Function

    '-- having分析
	'e.g. parseHaving("name")
    Private Function parseHaving(ByVal having)
		If Not AB.C.IsNul(having) Then
			having = " HAVING " & having
		Else
			having = ""
		End If
		having = ReplaceTable(having)
		parseHaving = having
    End Function

	'-- union分析
    Private Function parseUnion(ByVal union)
		If Not AB.C.IsNul(union) Then
			If AB.C.RegTest(Lcase(union), "^([ |]?)union\s+") Then
				union = " " & union
			Else
				union = " UNION " & union
			End If
		Else
			union = ""
		End If
		union = ReplaceTable(union)
		parseUnion = union
    End Function

	'处理替换数据表
	Private Function ReplaceTable(ByVal str)
		Dim Matches, Match
		'将__TABLE_NAME__这样的字符串替换成正规的表名,并且带上前缀和后缀
		'str = AB.C.RegReplace(str, "__([A-Z_-]+)__", s_tbPrefix & "$1" )
		Set Matches = AB.C.RegMatch(str, "__([A-Z_-]+)__")
		For Each Match in Matches
			str = Replace(str, Match.Value, s_tbPrefix & LCase(Match.SubMatches(0)))
		Next
		Set Matches = Nothing
		str = AB.C.RP(str, "#@", s_tbPrefix) '替换数据表前缀
		ReplaceTable = str
    End Function

End Class
%>